package com.smarttest.portal.service.timertask;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smarttest.portal.mapper.DbAutoTimertaskMapper;
import com.smarttest.portal.pojo.DbAutoTimertask;
import com.smarttest.portal.pojo.DbAutoTimertaskExample;
import com.smarttest.portal.pojo.DbAutoTimertaskWithBLOBs;
import com.smarttest.portal.service.Autog7Service;

@Service
public class AutoTimerTask {
	//ScheduledThreadPoolExecutor和timer都可以定时任务,timer所有任务都是串行的，缺点很大
//	static Timer timer = new Timer();
	private static int corePoolSize = 3;
	private static ScheduledThreadPoolExecutor st = new ScheduledThreadPoolExecutor(corePoolSize);
	private static Map<Integer,ScheduledFuture<?>> taskMap = new HashMap<Integer, ScheduledFuture<?>>();
	@Autowired
	Autog7Service Autog7Service;
	@Autowired
	DbAutoTimertaskMapper DbAutoTimertaskMapper;
	//定义一个static的connMgr对象的话 如果下面两个方法同时操作，一个关闭了jdbc，那么另一个操作数据库会报错。因为是同一个对象。所以对象只能自己new
	@PostConstruct
	public void excuteTimer () {	
		//设置执行时间
		System.out.println("启动定时任务");
		List<DbAutoTimertaskWithBLOBs> ls = DbAutoTimertaskMapper.selectByExampleWithBLOBs(new DbAutoTimertaskExample());
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
		for (DbAutoTimertaskWithBLOBs task: ls) {
			int type = task.getExctype();
			String []times = task.getRuntime().split(":");
			int runhour = Integer.parseInt(times[0]);
			int runmin = Integer.parseInt(times[1]);
			int runsecond = Integer.parseInt(times[2]);
			Runnable runnable = excuteTask(task.getEnvid(),task.getReleaseid(),task.getTestids(),type,task.getId());
			int hour = calendar.get(Calendar.HOUR_OF_DAY); 
			int minute = calendar.get(Calendar.MINUTE); 
			int second = calendar.get(Calendar.SECOND); 			
			if (runhour < hour || runhour == hour && runmin < minute 
					|| runhour == hour && runmin == minute && runsecond <= second) {
				calendar.add(Calendar.DAY_OF_MONTH, +1);
				year = calendar.get(Calendar.YEAR);
				month = calendar.get(Calendar.MONTH);
				day = calendar.get(Calendar.DAY_OF_MONTH);					
			}
	        calendar.set(year, month, day, runhour, runmin, runsecond);
			long initdelay = calendar.getTimeInMillis() - new Date().getTime();
			
			//一次
			if (type == 0) {
//				m2.put(i, r);
				ScheduledFuture<?> sf = st.schedule(runnable, initdelay,TimeUnit.MILLISECONDS);
				taskMap.put(ls.size()+1, sf);
			}
			//每天
			else if (type == 1) {	
				ScheduledFuture<?> sf = st.scheduleAtFixedRate(runnable, initdelay, 24*60*60*1000, TimeUnit.MILLISECONDS);
				taskMap.put(ls.size()+1, sf);
			}
		}	
	}
	/**
	 * 添加定时任务
	 * @param envid
	 * @param releaseid
	 * @param describing
	 * @param testids
	 * @param jobdetails
	 * @param exctype
	 * @param runtime
	 */
	@Transactional
	public void addTimerTask(int envid, int releaseid, String describing,String testids, String jobdetails, int exctype, String runtime) {	
		DbAutoTimertaskWithBLOBs tsk = new DbAutoTimertaskWithBLOBs();
		tsk.setDescribing(describing);
		tsk.setTestids(testids);
		tsk.setJobdetails(jobdetails);
		tsk.setExctype(exctype);
		tsk.setRuntime(runtime);
		tsk.setEnvid(envid);
		tsk.setReleaseid(releaseid);
		tsk.setCreatetime(new Date());		
		tsk.setDeleted(false);
		int tskid = DbAutoTimertaskMapper.insertAndGetId(tsk);
		int id = tsk.getId();
		if (tskid > 0) {
			Runnable runnable = excuteTask(envid,releaseid,testids,exctype, id);
			//设置执行时间
	        Calendar calendar = Calendar.getInstance();
	        int year = calendar.get(Calendar.YEAR);
	        int month = calendar.get(Calendar.MONTH);
	        int day = calendar.get(Calendar.DAY_OF_MONTH);
	        int hour = calendar.get(Calendar.HOUR_OF_DAY); 
			int minute = calendar.get(Calendar.MINUTE); 
			int second = calendar.get(Calendar.SECOND); 
	        String [] times = runtime.split(":");
			int runhour = Integer.parseInt(times[0]);
			int runmin = Integer.parseInt(times[1]);
			int runsecond = Integer.parseInt(times[2]);			
			if (runhour < hour || runhour == hour && runmin < minute 
					|| runhour == hour && runmin == minute && runsecond <= second) {
				calendar.add(Calendar.DAY_OF_MONTH, +1);
				year = calendar.get(Calendar.YEAR);
				month = calendar.get(Calendar.MONTH);
				day = calendar.get(Calendar.DAY_OF_MONTH);					
			}
	        calendar.set(year, month, day, runhour, runmin, runsecond);
			long initdelay = calendar.getTimeInMillis() - new Date().getTime();
//			Test s = new Test(3);
			Map<Integer,ScheduledFuture<?>> m = new HashMap<Integer, ScheduledFuture<?>>();
//			Map<Integer,Runnable> m2 = new HashMap<Integer, Runnable>();
			//一次
			if (exctype == 0) {
//				m2.put(i, r);
				ScheduledFuture<?> sf = st.schedule(runnable, initdelay,TimeUnit.MILLISECONDS);
				m.put(m.size()+1, sf);
			}
			//每天
			else if (exctype == 1) {	
				ScheduledFuture<?> sf = st.scheduleAtFixedRate(runnable, initdelay, 24*60*60*1000, TimeUnit.MILLISECONDS);
				m.put(m.size()+1, sf);
			}
		}
	}
	/**
	 * 执行一次任务
	 * @param envid
	 * @param releaseid
	 * @param testids
	 * @param exctype
	 * @param tskid
	 * @return
	 */
	@Transactional
	public Runnable excuteTask (final int envid,final int releaseid,final String testids,final int exctype, final int tskid) {
		Runnable task = new Runnable() {
            @Override
            public void run() {
            	Autog7Service.runTest(JSON.parseObject(testids),releaseid);
            	if (exctype == 0) {
            		st.remove(this);
            		DbAutoTimertaskWithBLOBs b = DbAutoTimertaskMapper.selectByPrimaryKey(tskid);
            		b.setDeleted(true);
            		DbAutoTimertaskMapper.updateByPrimaryKeySelective(b);
        		    System.out.println("一次定时任务运行完毕");
            	}
            }
        };
        return task;
	}
	
	class Test extends ScheduledThreadPoolExecutor{

		/**
		 * @param corePoolSize
		 */
		public Test(int corePoolSize) {
			super(corePoolSize);
			// TODO Auto-generated constructor stub
		}
		
		public void test(Runnable r,RunnableScheduledFuture<?> task) {
			decorateTask(r, task);
		}
//		public void test(Callable<?> c,RunnableScheduledFuture<?> task) {
//			decorateTask(c, task);
//		}
	}
}
